﻿/// <reference path="../../particletool/cubeshape.ts" />
/// <reference path="../../particletool/meshbatcher.ts" />
/// <reference path="../../particletool/particleshape.ts" />
/// <reference path="../../particletool/planeshape.ts" />
/// <reference path="../../particletool/particlesystem.ts" />
/// <reference path="../../particletool/sphereshape.ts" />

class HeightField
{
    _canvasEgret: egret3d.Egret3DCanvas;
    _view3D: egret3d.View3D;
    _cameraCtrl: egret3d.LookAtController;

    particleSystem: egret3d.ParticleSystem;

    start()
    {
        this.initCannon();

        this._canvasEgret = new egret3d.Egret3DCanvas();
        this._canvasEgret.x = 0;
        this._canvasEgret.y = 0;
        this._canvasEgret.width = window.innerWidth;
        this._canvasEgret.height = window.innerHeight;
        this._canvasEgret.start();

        var lightGroup = new egret3d.LightGroup();
        var light = new egret3d.DirectLight(new egret3d.Vector3D(0.1, -0.1, -1));
        light.diffuse = 0xffffff;
        light.intensity = 0.6;
        lightGroup.addLight(light);

        this._view3D = new egret3d.View3D(0, 0, window.innerWidth, window.innerHeight);
        this._view3D.camera3D.lookAt(new egret3d.Vector3D(0, -15, 6), new egret3d.Vector3D(0, 0, 0), new egret3d.Vector3D(0, 0, 1));
        this._view3D.backColor = 0xff333333;
        this._canvasEgret.addView3D(this._view3D);

        this._cameraCtrl = new egret3d.LookAtController(this._view3D.camera3D, new egret3d.Object3D());
        this._cameraCtrl.distance = 30;
        this._cameraCtrl.rotationX = 120;

        this.particleSystem = new egret3d.ParticleSystem(this._view3D);
        var material = new egret3d.ColorMaterial();
        this.particleSystem.setMat(material, lightGroup);
        this.particleSystem.addParticleByShape(this.getSelfPlaneShape(), (p, time) =>
        {
            if (!p.isinit)
            {
                p.lifeTime = 10000;
                p.isinit = true;
            }
        }, 1);

        var sizeX = 15;
        var sizeY = 15;
        for (var i = 0; i < sizeX - 1; i++)
        {
            for (var j = 0; j < sizeY - 1; j++)
            {
                if (i === 0 || i >= sizeX - 2 || j === 0 || j >= sizeY - 2)
                    continue;
                var sphereShape = new egret3d.Mesh(new egret3d.SphereGeometry(0.1, 16, 8), new egret3d.ColorMaterial());
                sphereShape.material.lightGroup = lightGroup;
                this._view3D.addChild3D(sphereShape);
                this.meshes.push(sphereShape);
            }
        }

        this._canvasEgret.addEventListener(egret3d.Event3D.ENTER_FRAME, this.update, this);
        egret3d.Input.addEventListener(egret3d.Event3D.RESIZE, this.onResize, this);

    }

    getSelfPlaneShape(): egret3d.ParticleShape
    {
        var particleshape: egret3d.ParticleShape = new egret3d.ParticleShape();

        var _segmentsW: number = 14;
        var _segmentsH: number = 14;

        var _width: number = 14;
        var _height: number = 14;
        
        var x: number, y: number;
        var numIndices: number;
        var base: number;
        var tw: number = _segmentsW + 1;
        var numVertices: number = (_segmentsH + 1) * tw;
        var stride: number = particleshape.vertexAttLength;
        var skip: number = stride - 15;

        numIndices = _segmentsH * _segmentsW * 6;

        particleshape.vertexCount = numVertices;
        particleshape.indexCount = numIndices;


        numIndices = 0;
        var point: egret3d.Vector3D = new egret3d.Vector3D();
        var index: number = 0;
        for (var yi: number = 0; yi <= _segmentsH; ++yi)
        {
            for (var xi: number = 0; xi <= _segmentsW; ++xi)
            {
                x = (xi / _segmentsW - .5) * _width;
                y = (yi / _segmentsH - .5) * _height;
                var z = 3;
                var anglespan = 2 * Math.PI / (_segmentsH + 1);
                if (xi == 0 || xi == _segmentsW || yi == 0 || yi == _segmentsH)
                {

                }
                else
                {
                    z = (Math.cos(anglespan * xi) * Math.cos(anglespan * yi) + 2);
                }

                particleshape.vertexArray[index++] = x;
                particleshape.vertexArray[index++] = y;
                particleshape.vertexArray[index++] = z;

                var normLen: number = 1 / Math.sqrt(x * x + y * y + z * z);
                
                particleshape.vertexArray[index++] = x * normLen;
                particleshape.vertexArray[index++] = y * normLen;
                particleshape.vertexArray[index++] = z * normLen;
                
                particleshape.vertexArray[index++] = 1;
                particleshape.vertexArray[index++] = 0;
                particleshape.vertexArray[index++] = 0;

                particleshape.vertexArray[index++] = 1;
                particleshape.vertexArray[index++] = 1;
                particleshape.vertexArray[index++] = 1;
                particleshape.vertexArray[index++] = 1;

                particleshape.vertexArray[index++] = xi / _segmentsW;
                particleshape.vertexArray[index++] = 1 - yi / _segmentsH;

                index += skip;

                if (xi != _segmentsW && yi != _segmentsH)
                {
                    base = xi + yi * tw;
                    var mult: number = 1;

                    particleshape.indexArray[numIndices++] = base * mult;
                    particleshape.indexArray[numIndices++] = (base + tw) * mult;
                    particleshape.indexArray[numIndices++] = (base + tw + 1) * mult;

                    particleshape.indexArray[numIndices++] = base * mult;
                    particleshape.indexArray[numIndices++] = (base + tw + 1) * mult;
                    particleshape.indexArray[numIndices++] = (base + 1) * mult;

                }
            }
        }
        return particleshape;
    }

    world: CANNON.World;
    hfBody: CANNON.Body;
    bodies: CANNON.Body[] = [];
    meshes: egret3d.Mesh[] = [];
    initCannon()
    {
        this.world = new CANNON.World();
        this.world.quatNormalizeSkip = 2;
        this.world.quatNormalizeFast = true;

        this.world.gravity.set(0, 0, -10);
        this.world.broadphase = new CANNON.NaiveBroadphase();

        var matrix = [];
        var sizeX = 15,
            sizeY = 15;
        for (var i = 0; i < sizeX; i++)
        {
            matrix.push([]);
            for (var j = 0; j < sizeY; j++)
            {
                var height = Math.cos(i / sizeX * Math.PI * 2) * Math.cos(j / sizeY * Math.PI * 2) + 2;
                if (i === 0 || i === sizeX - 1 || j === 0 || j === sizeY - 1)
                    height = 3;
                matrix[i].push(height);
            }
        }

        // Create the heightfield
        var hfShape = new CANNON.Heightfield(matrix, { elementSize: 1 });
        this.hfBody = new CANNON.Body({ mass: 0 });
        this.hfBody.addShape(hfShape);
        this.hfBody.position.set(-sizeX * hfShape.elementSize / 2 + 0.5, -sizeY / 2 + 0.5, 0);
        //this.hfBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
        this.world.addBody(this.hfBody);

        // Add spheres
        var mass = 1;
        for (var i = 0; i < sizeX - 1; i++)
        {
            for (var j = 0; j < sizeY - 1; j++)
            {
                if (i === 0 || i >= sizeX - 2 || j === 0 || j >= sizeY - 2)
                    continue;
                var sphereShape = new CANNON.Sphere(0.1);
                var sphereBody = new CANNON.Body({ mass: mass });
                sphereBody.addShape(sphereShape);
                sphereBody.position.set(0.25 + i, 0.25 + j, 3);
                sphereBody.position.vadd(this.hfBody.position, sphereBody.position);
                this.world.addBody(sphereBody);
                this.bodies.push(sphereBody);
            }
        }
    }

    update()
    {
        this._cameraCtrl.update();

        this.updatePhysics();
    }

    fps: number = 60;
    updatePhysics()
    {
        this.world.step(1 / this.fps);

        for (var i = 0; i < this.meshes.length; i++)
        {
            this.meshes[i].position = new egret3d.Vector3D(this.bodies[i].position.x, this.bodies[i].position.y, this.bodies[i].position.z);
            this.meshes[i].orientation = new egret3d.Quaternion(this.bodies[i].quaternion.x, this.bodies[i].quaternion.y, this.bodies[i].quaternion.z, this.bodies[i].quaternion.w);
        }
        
    }

    onResize(e: egret3d.Event3D)
    {
        this._view3D.width = this._canvasEgret.width;
        this._view3D.height = this._canvasEgret.height;
    }
}

window.onload = () =>
{
    var a = new HeightField();
    a.start();
};
